import { defineStore } from 'pinia'
import { ElMessage } from 'element-plus'
import { save } from '@/utils/savemessage'
import useMessageStore from '@/store/modules/messages'
import { WsState } from './types/type'
import useUserStore from '@/store/modules/user'
import {
    GET_CALLTO,
    SET_CALLTO,
    GET_INCOMINGCALL,
    SET_INCOMINGCALL,
    GET_ISCALLING,
    SET_ISCALLING,
    GET_VIDEOINFO,
    SET_VIDEOINFO,
    SET_CALLTYPE,
    GET_CALLTYPE,
    GET_RECEIVEDSDP,
    SET_RECEIVEDSDP,
} from '@/utils/keepCall'
import { reqUpdateUnRead } from '@/api/messages'
import pinia from '@/store'

let socket: any
const userStore = useUserStore(pinia)

const useWebSocketStore = defineStore('websocket', {
    state: (): WsState => ({
        isConnected: false, //用于判定用户是否连接WebSocket
        heartbeatInterval: null, //用于存储WebSocket心跳定时器
        missedHeartbeats: 0, //用于计数WebSocket丢失的心跳次数
        reconnectInterval: null, //用于储存WebSocket重连定时器
        callTo: GET_CALLTO(), //用于确认是否有给对方发起通话
        incomingCall: GET_INCOMINGCALL(), //用于确认是否有来电
        iscalling: GET_ISCALLING(), //用于确认是否在通话中
        receivedSDP: GET_RECEIVEDSDP(), //用于接收远程应答SDP描述
        videoInfo: GET_VIDEOINFO(), //来电好友的头像、名字等信息
        showMessage: '', //通话时的通知信息
        callType: GET_CALLTYPE(), //通话类型
        peer: null, //peer连接
        isRequestReconnect: false, //是否请求通话断线重连
        callReconnected: false, //通话断线重连是否成功
        newFriend: null, //如果有新值则重新获取好友列表和好友请求信息
        friendApply: false, // webSocket传输的好友验证消息类型
    }),
    actions: {
        //创建WebSocket连接
        async connectWebSocket() {
            if (!socket || socket.readyState === WebSocket.CLOSED) {
                socket = new WebSocket('ws://localhost:8080/api/ws/connection')
                socket.addEventListener('open', this.handleOpen)
                socket.addEventListener('close', this.handleClose)
                socket.addEventListener('error', this.handleError)
                socket.addEventListener('message', this.handleMessage)
            }
        },

        //销毁WebSocket连接
        disconnectWebSocket() {
            if (socket && socket.readyState === WebSocket.OPEN) {
                clearInterval(this.heartbeatInterval!) //关闭心跳定时器
                socket.close()
            }
        },

        //WebSocket变成打开状态后的默认事件
        handleOpen() {
            this.isConnected = true
            socket.send(JSON.stringify(userStore.userId))
            this.startHeartbeat() //开始心跳检测
            clearInterval(this.reconnectInterval) //清除重连定时器
        },

        //WebSocket变成关闭状态后的默认事件
        handleClose() {
            this.isConnected = false
            clearInterval(this.heartbeatInterval!) //清除心跳定时器
        },

        //WebSocket出错的默认事件
        handleError(event: any) {
            console.error('WebSocket出错:', event)
            this.startReconnect() //尝试重连
        },

        //WebSocket接收到后端返回的消息的默认事件
        async handleMessage(event: any) {
            if (event.data === 'pong') {
                // 收到 pong 响应时重置心跳计数
                this.missedHeartbeats = 0
                return
            }
            const receivedMessage = JSON.parse(event.data)
            //聊天信息的种类
            const validTypes = ['text', 'audio', 'video', 'emoji', 'file', 'picture']
            if (validTypes.includes(receivedMessage.message_type)) {
                const messageStore = useMessageStore()
                for (let i = 0; i < messageStore.conversations.length; i++) {
                    if (!messageStore.conversations[i].users.includes(receivedMessage.sender_id)) {
                        continue
                    }
                    if (!messageStore.chattingFriend) {
                        if (receivedMessage.sender_id === messageStore.conversations[i].users[0]) {
                            messageStore.conversations[i].unRead2++
                        } else {
                            messageStore.conversations[i].unRead1++
                        }
                        break
                    }
                    if (
                        messageStore.chattingFriend &&
                        messageStore.chattingFriend.userId === receivedMessage.sender_id
                    ) {
                        if (receivedMessage.sender_id === messageStore.conversations[i].users[0]) {
                            messageStore.conversations[i].unRead2 = 0
                            reqUpdateUnRead({
                                conversation_id: messageStore.conversations[i].conversation_id,
                                unRead2: 0,
                            })
                        } else {
                            messageStore.conversations[i].unRead1 = 0
                            reqUpdateUnRead({
                                conversation_id: messageStore.conversations[i].conversation_id,
                                unRead1: 0,
                            })
                        }
                        break
                    }
                    if (
                        messageStore.chattingFriend &&
                        messageStore.chattingFriend.userId !== receivedMessage.sender_id
                    ) {
                        if (receivedMessage.sender_id === messageStore.conversations[i].users[0]) {
                            messageStore.conversations[i].unRead2++
                        } else {
                            messageStore.conversations[i].unRead1++
                        }
                        break
                    }
                }
                //接收成功将消息存到本地和仓库中
                messageStore.conversations = save(messageStore.conversations, receivedMessage)
                return
            }
            if (receivedMessage.message_type === 'video_info') {
                const videoInfo = {
                    userId: receivedMessage.userId,
                    avatar: receivedMessage.avatar,
                    realname: receivedMessage.realname,
                }
                this.videoInfo = videoInfo
                this.callType = receivedMessage.callType
                this.incomingCall = true
                SET_VIDEOINFO(videoInfo)
                SET_CALLTYPE(receivedMessage.callType)
                SET_INCOMINGCALL(true)
                this.showMessage = receivedMessage.showMessage
                return
            }
            if (receivedMessage.message_type === 'video_end') {
                this.initializeWebsocketStore()
                this.showMessage = receivedMessage.showMessage
                return
            }
            if (receivedMessage.message_type === 'video_receive') {
                this.iscalling = true
                SET_ISCALLING(true)
                this.showMessage = receivedMessage.showMessage
                return
            }
            if (receivedMessage.message_type === 'video_refuse') {
                this.callTo = false
                SET_CALLTO(false)
                this.showMessage = receivedMessage.showMessage
                return
            }
            if (receivedMessage.message_type === 'SDP_offer') {
                this.receivedSDP = receivedMessage
                SET_RECEIVEDSDP(receivedMessage)
                return
            }
            if (receivedMessage.message_type === 'SDP_answer') {
                this.receivedSDP = receivedMessage
                SET_RECEIVEDSDP(receivedMessage)
                if (this.peer) {
                    await this.peer.setRemoteDescription(
                        new RTCSessionDescription(receivedMessage.data),
                    )
                }
                return
            }
            if (receivedMessage.message_type === 'ice') {
                if (this.peer) {
                    await this.peer.addIceCandidate(
                        new RTCIceCandidate(receivedMessage.iceCandidate),
                    )
                }
                return
            }
            if (receivedMessage.message_type === 'reconnect') {
                this.isRequestReconnect = true
                return
            }
            if (receivedMessage.message_type === 'callReconnectSuccess') {
                this.callReconnected = true
                return
            }
            if (receivedMessage.message_type === 'verify-require') {
                this.newFriend = receivedMessage.newFriend
            }
            if (receivedMessage.message_type === 'apply') {
                this.friendApply = true
            }
        },

        //将websocket仓库回归初始状态的方法
        initializeWebsocketStore() {
            this.callTo = false
            this.iscalling = false
            this.incomingCall = false
            SET_CALLTO(false)
            SET_ISCALLING(false)
            SET_INCOMINGCALL(false)
        },

        //前端向后端WebSocket发送消息的方法
        sendMessage(message: any) {
            if (socket && socket.readyState === WebSocket.OPEN) {
                socket.send(JSON.stringify(message))
            } else {
                ElMessage.error('网络未连接，无法发送消息')
            }
        },

        //WebSocket进行连接状态检测的方法
        startHeartbeat() {
            this.heartbeatInterval = setInterval(() => {
                if (socket.readyState === WebSocket.OPEN) {
                    if (this.missedHeartbeats >= 3) {
                        console.error('与服务器的连接丢失，尝试重新连接...')
                        this.disconnectWebSocket()
                        this.connectWebSocket() //尝试重新连接
                    } else {
                        socket.send('ping') //发送心跳消息
                        this.missedHeartbeats++
                    }
                }
            }, 60000) // 每60秒发送一次心跳
        },

        //WebSocket断开连接后尝试重连的方法
        startReconnect() {
            //已经在重连，不重复启动
            if (this.reconnectInterval) {
                return
            }
            this.reconnectInterval = setInterval(() => {
                this.connectWebSocket() //尝试重连
            }, 5000)
        },

        async sendSDP(author: string, sender_id: number, receiver_id: number) {
            //创建并发送SDP
            if (author === 'offer') {
                if (this.peer) {
                    const data = await this.peer.createOffer()
                    await this.peer.setLocalDescription(data)

                    const answerMessage = {
                        message_type: `SDP_${author}`,
                        sender_id: sender_id,
                        receiver_id: receiver_id,
                        data: data,
                    }
                    this.sendMessage(answerMessage)
                }
            } else if (author === 'answer') {
                if (this.peer) {
                    //接收方接收并设置远程SDP描述
                    await this.peer.setRemoteDescription(
                        new RTCSessionDescription(this.receivedSDP.data),
                    )
                    const data = await this.peer.createAnswer()
                    await this.peer.setLocalDescription(data)

                    const answerMessage = {
                        message_type: `SDP_${author}`,
                        sender_id: sender_id,
                        receiver_id: receiver_id,
                        data: data,
                    }
                    this.sendMessage(answerMessage)
                }
            }
        },
    },
})

export default useWebSocketStore
